home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / utils / traceLog.c < prev    next >
C/C++ Source or Header  |  1991-07-25  |  15KB  |  513 lines

  1. /* 
  2.  * traceLog.c --
  3.  *
  4.  *    This files implements a generalized tracing facility.  
  5.  *    TraceLog_Buffer    contains information about the number and size of
  6.  *    the elements in a circular buffer that is dynamically allocated by
  7.  *    TraceLog_Init.  Calls to TraceLog_Insert add a time-stamped traceLog
  8.  *    record to the buffer.  A buffer of traceLog records can be dumped to
  9.  *    user space via calls to TraceLog_Dump.
  10.  *
  11.  *    The main difference between these routines and the routines in
  12.  *    traceLog.c are that these routines are for continuous dumping of
  13.  *    data to user level.  They are set up to buffer and block data
  14.  *    for dumping in large chunks to user level.  Also, they handle
  15.  *    variable-sized records.
  16.  *
  17.  *     These routines are for the SOSP91 paper.
  18.  *
  19.  * Copyright 1991 Regents of the University of California
  20.  * Permission to use, copy, modify, and distribute this
  21.  * software and its documentation for any purpose and without
  22.  * fee is hereby granted, provided that this copyright
  23.  * notice appears in all copies.  The University of California
  24.  * makes no representations about the suitability of this
  25.  * software for any purpose.  It is provided "as is" without
  26.  * express or implied warranty.
  27.  */
  28.  
  29. #ifndef lint
  30. static char rcsid[] = "$Header: /sprite/src/kernel/utils/RCS/traceLog.c,v 1.9 91/07/24 22:18:19 kupfer Exp $ SPRITE (Berkeley)";
  31. #endif not lint
  32.  
  33. #include "sprite.h"
  34. #include "traceLog.h"
  35. #include "bstring.h"
  36. #include "timer.h"
  37. #include "stdlib.h"
  38. #include "sysStats.h"
  39. #include "sys.h"
  40. #include "sync.h"
  41. #include "vm.h"
  42. #include "mach.h"
  43. #include <stdio.h>
  44. #include <main.h>
  45. #include <string.h>
  46. #include <status.h>
  47.  
  48. #define CHECKCONSIST
  49.  
  50. static void TraceLog_FlushBuffer _ARGS_((TraceLog_Header *tracePtr));
  51.  
  52. static Sync_Lock traceLogLock = Sync_LockInitStatic("Utils:traceLog_Mutex");
  53. #define LOCKPTR &traceLogLock
  54.  
  55. Sync_Condition bufferFullCondition; /* Condition that we have a full block
  56.                        to give the user. */
  57.  
  58. extern int vmShmDebug;    /* Ken's handy debug flag. */
  59.  
  60. /*
  61.  * Global tracing inhibit flag so it is easy to turn off all system tracing.
  62.  */
  63. Boolean traceLog_Disable = TRUE;
  64.  
  65. /*
  66.  * Invariants for the trace pointers.
  67.  * If tracePtr->blocked:
  68.  *      firstNewBuffer points to the first buffer with new data.
  69.  *    currentBuffer points to the buffer we're about to fill.
  70.  *    (i.e. currentBuffer = firstNewBuffer when we first block)
  71.  * If !tracePtr->blocked:
  72.  *    firstNewBuffer points to the first buffer with new (undumped) data.
  73.  *    currentBuffer points to the buffer we're currently loading.
  74.  *      If there are no full buffers, firstNewBuffer=currentBuffer
  75.  */
  76.  
  77.  
  78. /*
  79.  *----------------------------------------------------------------------
  80.  *
  81.  * TraceLog_Init --
  82.  *
  83.  *    Allocate and initialize a circular traceLog buffer.
  84.  *
  85.  * Results:
  86.  *    None.
  87.  *
  88.  * Side effects:
  89.  *    Memory is allocated for the individual buffer records.  Note 
  90.  *    that the TraceLog_Header is assumed to be allocated
  91.  *    (statically or dynamically) by the calling routine, and its values
  92.  *    are initialized in this routine.
  93.  *
  94.  *----------------------------------------------------------------------
  95.  */
  96.  
  97. void
  98. TraceLog_Init(tracePtr, numBuffers, size, flags, version)
  99.     register TraceLog_Header *tracePtr;    /* pointer to tracing info */
  100.     int numBuffers;            /* number of buffers to allocate */
  101.     int size;                /* size of each buffer area */
  102.     int flags;                /* TRACELOG_NO_TIMES */
  103.     int version;
  104. {
  105.     int i;
  106.     Time time;
  107.     Timer_Ticks ticks;
  108.  
  109.     LOCK_MONITOR;
  110.     tracePtr->numBuffers = numBuffers;
  111.     tracePtr->flags = flags;
  112.     tracePtr->dataSize = size;
  113.     tracePtr->firstNewBuffer = 0;
  114.     tracePtr->currentBuffer = 0;
  115.     tracePtr->currentOffset = 0;
  116.     tracePtr->blocked = 0;
  117.     tracePtr->lostRecords = 0;
  118.     tracePtr->totalNumRecords = 0;
  119.     tracePtr->totalLostRecords = 0;
  120.     tracePtr->hdr.machineID = rpc_SpriteID;
  121.     strncpy(tracePtr->hdr.machineType, mach_MachineType, SYS_TRACELOG_TYPELEN);
  122.     tracePtr->hdr.kernel[0] = version;
  123.     tracePtr->hdr.kernel[1] = '/';
  124.     strncpy(tracePtr->hdr.kernel+2, SpriteVersion(), SYS_TRACELOG_KERNELLEN-2);
  125.     Timer_GetRealTimeOfDay(&time, (int *)NIL, (Boolean *)NIL);
  126.     Timer_GetCurrentTicks(&ticks);
  127.     Timer_SubtractTicks(*(Time *)&time, *(Time *)&ticks,
  128.         (Time *)tracePtr->hdr.bootTime);
  129.  
  130.     tracePtr->buffers =
  131.         (TraceLog_Buffer *) malloc(numBuffers *
  132.             sizeof(TraceLog_Buffer));
  133.     for (i=0;i<numBuffers;i++) {
  134.     tracePtr->buffers[i].size = 0;
  135.     tracePtr->buffers[i].numRecords = 0;
  136.     tracePtr->buffers[i].lostRecords = 0;
  137.     tracePtr->buffers[i].data = (Address) malloc(size);
  138. #ifdef CHECKCONSIST
  139.     tracePtr->buffers[i].mode = TRACELOG_UNUSED;
  140. #endif
  141.     }
  142. #ifdef CHECKCONSIST
  143.         tracePtr->buffers[0].mode = TRACELOG_INUSE;
  144. #endif
  145.     if (2*sizeof(int) < sizeof(Timer_Ticks)) {
  146.     printf("Warning: Timer_Ticks structure is too big for trace\n");
  147.     }
  148.     UNLOCK_MONITOR;
  149.  
  150. }
  151.  
  152.  
  153. /*
  154.  *----------------------------------------------------------------------
  155.  *
  156.  * TraceLog_Insert --
  157.  *
  158.  *    Save a time stamp and any client-specific data in a circular buffer.
  159.  *
  160.  * Results:
  161.  *    None.
  162.  *
  163.  * Side effects:
  164.  *    Record the information in a traceLog record and advance the
  165.  *    circular buffer pointer.
  166.  *
  167.  *----------------------------------------------------------------------
  168.  */
  169. #define INC_BUFNUM(x) ((x)=((x)+1>=tracePtr->numBuffers?0:(x)+1))
  170. #define REC_HEADER_SIZE (sizeof(Sys_TracelogRecord)-sizeof(ClientData))
  171. void
  172. TraceLog_Insert(tracePtr, dataPtr, origSize, flags)
  173.     TraceLog_Header *tracePtr;    /* The trace log info structure. */
  174.     Address dataPtr;        /* Pointer to the record. */
  175.     int    origSize;        /* Length in bytes of the record. */
  176.     int flags;
  177. {
  178.     Address traceDataAddr;
  179.     Sys_TracelogRecord traceRec;
  180.     int headerSize;
  181.     int size;
  182.  
  183.     if (traceLog_Disable || tracePtr == (TraceLog_Header *)NIL ||
  184.         tracePtr->flags & TRACELOG_INHIBIT) {
  185.     return;
  186.     }
  187.  
  188.     size = (origSize+3)&~3;    /* Make size word aligned. */
  189.  
  190.     LOCK_MONITOR;
  191.  
  192.     tracePtr->totalNumRecords++;
  193.  
  194.     if (size+REC_HEADER_SIZE > tracePtr->dataSize) {
  195.     printf("Record too big: %d\n", size);
  196.     tracePtr->lostRecords++;
  197.     tracePtr->totalLostRecords++;
  198.     UNLOCK_MONITOR;
  199.     return;
  200.     }
  201.  
  202.     /*
  203.      * Check if we've filled a buffer.
  204.      */
  205.     if (!tracePtr->blocked && (tracePtr->currentOffset+size+REC_HEADER_SIZE >
  206.         tracePtr->dataSize)) {
  207.     TraceLog_FlushBuffer(tracePtr);
  208.     }
  209.  
  210.     if (vmShmDebug) {
  211.     printf("buf=%x, num=%d, bytes: %d, flags: %x\n", tracePtr->buffers,
  212.         tracePtr->currentBuffer,size, flags);
  213.     }
  214.  
  215.     /*
  216.      * Check if we've run out of buffers.  If so, skip this record
  217.      * and keep track of how many we've lost.
  218.      */
  219.     if (tracePtr->blocked) {
  220.     if (vmShmDebug) {
  221.         printf("Trace buffer overflow!\n");
  222.     }
  223.     tracePtr->lostRecords++;
  224.     tracePtr->totalLostRecords++;
  225.     UNLOCK_MONITOR;
  226.     return;
  227.     }
  228.  
  229. #ifdef CHECKCONSIST
  230.     if (tracePtr->buffers[tracePtr->currentBuffer].mode != TRACELOG_INUSE) {
  231.     printf("Warning: buffer# %d has mode %d, not INUSE\n",
  232.         tracePtr->currentBuffer, tracePtr->buffers[tracePtr->
  233.         currentBuffer].mode);
  234.     }
  235.     tracePtr->buffers[tracePtr->currentBuffer].mode = TRACELOG_INUSE;
  236. #endif
  237.     traceDataAddr = tracePtr->buffers[tracePtr->currentBuffer].data +
  238.         tracePtr->currentOffset;
  239.  
  240.     if ( !(tracePtr->flags & TRACELOG_NO_TIMES)) {
  241.     Timer_GetCurrentTicks((Timer_Ticks *)traceRec.time);
  242.     headerSize = REC_HEADER_SIZE;
  243.     } else {
  244.     headerSize = sizeof(int);
  245.     }
  246.     traceRec.recordLen = (size+headerSize)|(flags<<16);
  247.     bcopy((Address)&traceRec, traceDataAddr, headerSize);
  248.     bcopy(dataPtr, traceDataAddr+headerSize, origSize);
  249.     tracePtr->buffers[tracePtr->currentBuffer].numRecords++;
  250.     tracePtr->currentOffset += size+headerSize;
  251.     if (tracePtr->flags & TRACELOG_NO_BUF) {
  252.     TraceLog_FlushBuffer(tracePtr);
  253.     }
  254.     UNLOCK_MONITOR;
  255. }
  256.  
  257. /*
  258.  *----------------------------------------------------------------------
  259.  *
  260.  * TraceLog_FlushBuffer --
  261.  *
  262.  *    We're done with the record, so we want to send it off.
  263.  *
  264.  * Results:
  265.  *    None.
  266.  *
  267.  * Side effects:
  268.  *    The information is filled in for the currentBuffer.
  269.  *    The currentBuffer is incremented to the next buffer.
  270.  *    The data is made available for the consumer.
  271.  *----------------------------------------------------------------------
  272.  */
  273. static void
  274. TraceLog_FlushBuffer(tracePtr)
  275.     register TraceLog_Header *tracePtr;
  276. {
  277.     tracePtr->buffers[tracePtr->currentBuffer].size =
  278.         tracePtr->currentOffset;
  279. #ifdef CHECKCONSIST
  280.     if (tracePtr->buffers[tracePtr->currentBuffer].mode != TRACELOG_INUSE) {
  281.     printf("Warning: buffer# %d has mode %d, not INUSE\n",
  282.         tracePtr->currentBuffer, tracePtr->buffers[tracePtr->
  283.         currentBuffer].mode);
  284.     }
  285.     tracePtr->buffers[tracePtr->currentBuffer].mode = TRACELOG_DONE;
  286. #endif
  287.     INC_BUFNUM(tracePtr->currentBuffer);
  288.     tracePtr->currentOffset = 0;
  289.     Sync_Broadcast(&bufferFullCondition);
  290.     if (tracePtr->currentBuffer == tracePtr->firstNewBuffer) {
  291.     tracePtr->blocked = 1;
  292.     }
  293. #ifdef CHECKCONSIST
  294.     else {
  295.     if (tracePtr->buffers[tracePtr->currentBuffer].mode !=
  296.         TRACELOG_UNUSED) {
  297.         printf("Warning: buffer# %d has mode %d, not UNUSED\n",
  298.             tracePtr->currentBuffer, tracePtr->buffers[tracePtr->
  299.             currentBuffer].mode);
  300.     }
  301.     tracePtr->buffers[tracePtr->currentBuffer].mode = TRACELOG_INUSE;
  302.     }
  303. #endif
  304. }
  305.  
  306.  
  307. /*
  308.  *----------------------------------------------------------------------
  309.  *
  310.  * TraceLog_Dump --
  311.  *
  312.  *    Dump traceLog records into the user's address space.  Data is copied
  313.  *    in the following order:
  314.  *
  315.  *    (1) The number of records being copied is copied.
  316.  *    (2) numRecs TraceLog_Records are copied.
  317.  *    (3) If traceLogData is non-NIL, numRecs records of traceData are copied.
  318.  *
  319.  * Results:
  320.  *    The result from Vm_CopyOut is returned, in addition to the
  321.  *    data specified above.
  322.  *
  323.  * Side effects:
  324.  *    Data is copied out to the user's address space.
  325.  *
  326.  *----------------------------------------------------------------------
  327.  */
  328.  
  329. ReturnStatus
  330. TraceLog_Dump(tracePtr, dataAddr, hdrAddr)
  331.     register TraceLog_Header *tracePtr;
  332.     Address dataAddr;
  333.     Address hdrAddr;
  334. {
  335.     ReturnStatus status = SUCCESS;
  336.     Boolean    abortedBySignal = FALSE;
  337.  
  338.     if (tracePtr == (TraceLog_Header *) NIL) {
  339.     printf("TraceLog_Dump: traceLog buffer not initialized.\n");
  340.     tracePtr->hdr.numBytes = 0;
  341.     tracePtr->hdr.numRecs = 0;
  342.     status = Vm_CopyOut(sizeof(Sys_TracelogHeaderKern),
  343.         (Address) &tracePtr->hdr, (Address)hdrAddr);
  344.     return(status);
  345.     }
  346.  
  347.     LOCK_MONITOR;
  348.  
  349.     /*
  350.      * Wait for a buffer to fill.
  351.      */
  352.     while (!tracePtr->blocked &&
  353.         tracePtr->firstNewBuffer==tracePtr->currentBuffer) {
  354.     if (Sync_Wait(&bufferFullCondition,TRUE) == TRUE) {
  355.         abortedBySignal = TRUE;
  356.         break;
  357.     }
  358.     }
  359.  
  360.     if (abortedBySignal) {
  361.     /*
  362.      * Forcibly flush the record.
  363.      */
  364.     tracePtr->buffers[tracePtr->currentBuffer].size =
  365.         tracePtr->currentOffset;
  366.     tracePtr->currentOffset = 0;
  367. #ifdef CHECKCONSIST
  368.     tracePtr->buffers[tracePtr->currentBuffer].mode = TRACELOG_DONE;
  369. #endif
  370.     INC_BUFNUM(tracePtr->currentBuffer);
  371.     }
  372.     
  373.  
  374. #ifdef CHECKCONSIST
  375.     if (tracePtr->buffers[tracePtr->firstNewBuffer].mode != TRACELOG_DONE) {
  376.     printf("Warning: buffer# %d has mode %d, not DONE\n",
  377.         tracePtr->firstNewBuffer, tracePtr->buffers[tracePtr->
  378.         firstNewBuffer].mode);
  379.     }
  380.     tracePtr->buffers[tracePtr->firstNewBuffer].mode = TRACELOG_UNUSED;
  381. #endif
  382.  
  383.     /*
  384.      * Copy the information into the output header buffer.
  385.      */
  386.     tracePtr->hdr.numBytes = tracePtr->buffers[tracePtr->firstNewBuffer].size;
  387.     tracePtr->hdr.numRecs =
  388.         tracePtr->buffers[tracePtr->firstNewBuffer].numRecords;
  389.     tracePtr->hdr.lostRecords = 
  390.         tracePtr->buffers[tracePtr->firstNewBuffer].lostRecords;
  391.     if (vmShmDebug) {
  392.     printf("Lost = %d\n", tracePtr->hdr.lostRecords);
  393.     }
  394.     /*
  395.      * Initialize the now-free buffer.
  396.      */
  397.     tracePtr->buffers[tracePtr->firstNewBuffer].numRecords=0;
  398.     tracePtr->buffers[tracePtr->firstNewBuffer].lostRecords=0;
  399.  
  400.     if (tracePtr->blocked) {
  401.     if (vmShmDebug) {
  402.         printf("Unblocked: lost = %d\n", tracePtr->lostRecords);
  403.     }
  404.     tracePtr->blocked = 0;
  405.     tracePtr->buffers[tracePtr->currentBuffer].lostRecords=
  406.         tracePtr->lostRecords;
  407. #ifdef CHECKCONSIST
  408.     tracePtr->buffers[tracePtr->currentBuffer].mode = TRACELOG_INUSE;
  409. #endif
  410.     }
  411.     tracePtr->lostRecords = 0;
  412.  
  413.     status = Vm_CopyOut(tracePtr->hdr.numBytes, tracePtr->buffers
  414.         [tracePtr->firstNewBuffer].data, dataAddr);
  415.  
  416.     if (status != SUCCESS) {
  417.     printf("Dump failed: status= %d, addr = %x\n", status, dataAddr);
  418.     printf("numBytes: %d, srcAddr: %x, dstAdr: %x\n",
  419.         tracePtr->hdr.numBytes,
  420.         tracePtr->buffers[tracePtr->firstNewBuffer].data, dataAddr);
  421.     UNLOCK_MONITOR;
  422.     return status;
  423.     }
  424.  
  425.     INC_BUFNUM(tracePtr->firstNewBuffer);
  426.  
  427.     status = Vm_CopyOut(sizeof(Sys_TracelogHeaderKern),
  428.         (Address) &tracePtr->hdr, (Address)hdrAddr);
  429.  
  430.     UNLOCK_MONITOR;
  431.     if ((status == SUCCESS) && (abortedBySignal)) {
  432.     status = GEN_ABORTED_BY_SIGNAL;
  433.     }
  434.     return status;
  435. }
  436.  
  437.  
  438. /*
  439.  *----------------------------------------------------------------------
  440.  *
  441.  * TraceLog_Reset --
  442.  *
  443.  *    Reset the trace log structures.
  444.  *
  445.  * Results:
  446.  *    None.
  447.  *
  448.  * Side effects:
  449.  *    The trace structure is reinitialized.
  450.  *
  451.  *----------------------------------------------------------------------
  452.  */
  453.  
  454. void
  455. TraceLog_Reset(tracePtr)
  456.     register TraceLog_Header *tracePtr;    /* pointer to tracing info */
  457. {
  458.     int i;
  459.     LOCK_MONITOR;
  460.     tracePtr->firstNewBuffer = 0;
  461.     tracePtr->currentBuffer = 0;
  462.     tracePtr->currentOffset = 0;
  463.     tracePtr->blocked = 0;
  464.     tracePtr->totalNumRecords = 0;
  465.     tracePtr->totalLostRecords = 0;
  466.     for (i=0;i<tracePtr->numBuffers;i++) {
  467.     tracePtr->buffers[i].size = 0;
  468.     tracePtr->buffers[i].numRecords = 0;
  469.     tracePtr->buffers[i].lostRecords = 0;
  470. #ifdef CHECKCONSIST
  471.     tracePtr->buffers[i].mode = TRACELOG_UNUSED;
  472. #endif
  473.     }
  474. #ifdef CHECKCONSIST
  475.     tracePtr->buffers[0].mode = TRACELOG_INUSE;
  476. #endif
  477.     UNLOCK_MONITOR;
  478. }
  479.  
  480. /*
  481.  *----------------------------------------------------------------------
  482.  *
  483.  * TraceLog_Finish --
  484.  *
  485.  *    Free the trace log structures.
  486.  *
  487.  * Results:
  488.  *    None.
  489.  *
  490.  * Side effects:
  491.  *    Everything is freed up.
  492.  *
  493.  *----------------------------------------------------------------------
  494.  */
  495.  
  496. void
  497. TraceLog_Finish(tracePtr)
  498.     register TraceLog_Header *tracePtr;    /* pointer to tracing info */
  499. {
  500.     int i;
  501.  
  502.     LOCK_MONITOR;
  503.     printf("Trace done: %d records, %d lost, %d successful\n",
  504.     tracePtr->totalNumRecords, tracePtr->totalLostRecords,
  505.     tracePtr->totalNumRecords-tracePtr->totalLostRecords);
  506.     for (i=0;i<tracePtr->numBuffers;i++) {
  507.     free(tracePtr->buffers[i].data);
  508.     }
  509.     free ((Address)tracePtr);
  510.     UNLOCK_MONITOR;
  511.  
  512. }
  513.